



#include "tcpserver.hpp"
#include "util.hpp"
#include <sstream>
#include <functional>
#include <unordered_map>
#include"session.hpp"
const string space = " ";
const string cline = "\r\n";
const string segkv = ": ";
const string webroot = "./wwwroot";
const string frontpage = "index.html";
class httprequest
{
public:
    httprequest() : _is_interaction(0) {}
    string serialize() { return string(); }

    void fillinfo(string s)
    {
        // GET / HTTP/1.1
        stringstream ss(s);
        ss >> _methond >> _uri >> _version;
    }
    void revise_uri()
    {
        //./wwwroot/index.html
        if (_uri == "/")
        {
            _uri = webroot + "/" + frontpage;
        }
        // ./wwwroot/a/b/c.html
        else
        {
            _uri = webroot + _uri;
        }
    };
    bool deserialize(string& req)
    {
        string requestline;                                // req中获取请求行到里面
        bool ans = util::getline(req, requestline, cline); // 调用工具类的静态成员函数
        fillinfo(requestline);                             // 填充uri/方法/版本等信息
        revise_uri();                                      // 修正uri
        if (!ans)
            return 0;
        // 分析是get还是post请求：
        if (_methond == "GET")
        {
            int pos = _uri.find('?', 0);
            // 1·uri带参数：

            if (pos != string::npos)
            {
                _is_interaction = 1; // 进行数据交互的标记
                _arg = _uri.substr(pos + 1);
                _uri = _uri.substr(0, pos);

            }
            // 2·uri不带参数：
            else
            {
                // 不处理

            }

            //判断有无cookie：
            while (1)
            {
                util::getline(req, requestline, cline);

                if (requestline.size())
                {
                    int pos = requestline.find(segkv, 0);
                    string k = requestline.substr(0, pos);
                    string v = requestline.substr(pos + segkv.size());
                    _header[k] = v;
                    //判断是否请求头存在对应的cookie：
                    if (k == "Cookie")
                    {
                        int pos = v.rfind('=');
                        _password = v.substr(pos + 1);
                    }

                }
                else {
                    break;
                }
            }
        }
        else if (_methond == "POST")
        {
            _is_interaction = 1; // 进行数据交互的标记

            while (1)
            {
                util::getline(req, requestline, cline);
                if (requestline.size())
                {
                    int pos = requestline.find(segkv, 0);
                    string k = requestline.substr(0, pos);
                    string v = requestline.substr(pos + segkv.size());
                    _header[k] = v;
                    if (k == "Content-Length")
                        _post_text_length = stoi(v);
                    //判断是否请求头存在对应的cookie：
                    if (k == "Cookie")
                    {
                        int pos = v.rfind('=');
                        _password = v.substr(pos + 1);
                    }
                }
                // 读到空行：
                else
                {
                    // 提取正文内容：//这里注意正文这行无\r\n
                    _post_text = req.substr(0, _post_text_length);
                    break;
                }
            }
        }

        return 1;
    }

    string get_uri() { return _uri; }
    bool get_interaction() { return _is_interaction; }
    string get_arg() { return _arg; }
    string get_posttext() { return _post_text; }
    string get_methond() { return _methond; }
    string get_password() { return _password; }
    ~httprequest() {}

private:
    string _methond;
    string _uri;
    string _version;
    string _text;
    string _arg;           // uri请求参数
    int _post_text_length; // post正文长度
    string _post_text;
    bool _is_interaction; // 进行数据交互的标记
    unordered_map<string, string> _header;
    string _password; // 记录用户正确的输入密码/还可以是对应的sessionid
};

class httpresponse
{
public:
    httpresponse() {}
    string serialize()
    {
        string httpans;
        httpans = httpans + _version + space + to_string(_code) + space + _describle + cline;

        for (auto& eve : _header)
        {
            httpans = httpans + eve.first + segkv + eve.second + cline;
        }
        // 添加cookie：
        for (auto c : _cookies)
        {
            httpans = httpans + c + cline;
        }
        httpans = httpans + cline + _text;
        return httpans;
    }

    bool deserialize(string& req)
    {
        return 1;
    }
    void set_route(string r)
    {
        _route = r;
    }

    // cookie测试：

    // 获得时间：
    string get_mon(int month)
    {
        vector<string> months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
        return months[month];
    }
    string get_week(int day)
    {
        vector<string> weekdays = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
        return weekdays[day];
    }
    string expires_time(int te)
    {
        time_t curtime = time(nullptr) + te;
        struct tm* pm = gmtime(&curtime); // 可以认为传递指针为了防止拷贝，返回指针可以认为是便于指针访问
        char buff[1024];
        snprintf(buff, sizeof(buff), "%s, %02d %s %d %02d:%02d:%02d UTC", get_week(pm->tm_wday).c_str(),
            pm->tm_mday,
            get_mon(pm->tm_mon).c_str(),
            pm->tm_year + 1900,
            pm->tm_hour,
            pm->tm_min,
            pm->tm_sec);
        return buff;
    }

    void set_cookie_username(string username)
    {
        string cookie;
        cookie = "Set-Cookie: username=" + username + "; expires=" + expires_time(300) + "; path=/;";
        _cookies.emplace_back(cookie);
    }
    void set_cookie_password(string password)
    {
        string cookie;
        cookie = "Set-Cookie: password=" + password + "; expires=" + expires_time(300) + "; path=/;";
        _cookies.emplace_back(cookie);
    }
    void set_cookie_session(string session_id) {
        string cookie;
        cookie = "Set-Cookie: sessionid=" + session_id + ";";
        _cookies.emplace_back(cookie);
    }
    void setcode(int code)
    {
        _code = code;
        switch (code)
        {
        case 404:
            _describle = "NOT FOUND";
            break;
        case 200:
            _describle = "OK";
            break;
        case 301:
            _describle = "Moved Permanently";
            break;
        case 302:
            _describle = "See Other";
        default:
            break;
        }
    }
    void setheader(string k, string v)
    {
        auto pos = _header.find(k);
        if (pos != _header.end())
            return;
        _header[k] = v;
    }
    string getsuffix(string tar)
    {
        int pos = tar.rfind('.');
        if (pos == string::npos)
        {
            return "text/html";
        }
        string suffix = tar.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == "png")
            return "image/png";
        else if (suffix == ".gif")
        {
            return "image/gif";
        }
        else if (suffix == ".mp4")
        {
            return "video/mp4";
        }
        else
            return "";
    }
    bool make_response()
    {
        bool ans = util::readfile(_text, _route);
        if (_route == "./wwwroot/favicon.ico")
        {
            use_log(loglevel::DEBUG) << "用户请求 " << _route << " 不做处理";
            return false;
        }
        if (_route == "./wwwroot/redirect")
        {
            setcode(301); // 永久重定向：第一次被浏览器记录保存，剩下的再访问就直接到location目的网址访问
            setheader("Location", "https://blog.csdn.net/2401_82648291?type=lately");
            return true;
        }
        // 每次清空一下：
        _text = "";
        // 找不到对应得到文件
        if (!ans)
        {               // 读取404文件：
                        // use_log(loglevel::DEBUG) << "用户查找 " << _route << " not found";
                        // setcode(404);
                        // _route = webroot + "/404.html";
                        // util::readfile(_text, _route);
                        // setheader("Content-Type", getsuffix(_route));
                        // setheader("Content-Length", to_string(util::filesize(_route)));
            setcode(302); // 临时重定向，每次访问到指定网址就拿到对应的location里的网址进行访问，浏览器不进行保存！
            setheader("Location", "http://123.249.104.207:8080/404.html");
        }
        else
        {
            // wwwroot存在该文件：
            use_log(loglevel::DEBUG) << "读取文件 " << _route;
            setcode(200);
            util::readfile(_text, _route);
            //对于答复，响应正文的类型和响应正文的长度是必须的： 
            setheader("Content-Type", getsuffix(_route));
            setheader("Content-Length", to_string(util::filesize(_route)));
        }
        return 1;
    }

    string get_route() { return _route; }
    ~httpresponse() {}

private:
    string _version = "HTTP/1.1";
    string _text;
    int _code;
    string _describle;
    string _route;
    unordered_map<string, string> _header;
    vector<string> _cookies;
};
using func_t = function<void(httprequest&, httpresponse&)>;
class http
{

public:
    http(uint16_t port) : _tser(make_unique<tcpserver>(port)) {}

    void getrequest(shared_ptr<Socket>& sock, inetaddr ir)
    {
        string buff;
        sock->Recv(buff); // 这里暂时默认一次性能读到完整的请求
        // std::cout << "##########################" << std::endl;
        // std::cout << buff;
        // std::cout << "##########################" << std::endl;
        httprequest re;
        if (re.deserialize(buff)) // 假设提取完报头就能正确反序列化
        {
            httpresponse res;
            res.set_route(re.get_uri());

            // 构建答复的路径两端需要交互（动态）：
            if (re.get_interaction())
            { // uri中获得对应的方法：
                int pos = re.get_uri().rfind('/');
                string way = re.get_uri().substr(pos + 1);
                // 调用请求服务对应的回调函数进行res构建：
                if (_route.find(way) == _route.end())
                {
                    // 返回404页面
                    res.set_route("./wwwroot/404.html");
                    res.make_response();
                }
                else
                {
                    _route[way](re, res); // 只是对应的res确定好_route即set_route
                    res.make_response();
                }
                string ans = res.serialize(); // 序列化发送
                sock->Send(ans);
            }

            // 两端不需要交互（静态）：
            else
            {
                if (res.make_response()) // 读取响应文
                {
                    string ans = res.serialize(); // 序列化发送
                    sock->Send(ans);
                }
            }
        }
    }
    void start()
    {
        _tser->start([this](shared_ptr<Socket>& sock, inetaddr ir)
            {
                use_log(loglevel::DEBUG) << ir.get_userinfo() << " 正在访问！ ";

                this->getrequest(sock, ir); // this指针不能引用捕捉：不允许改变this指针的指向
            });
    }
    void add_route(string src, func_t route)
    {
        auto iter = _route.find(src);
        if (iter != _route.end())
            return;
        _route[src] = route;
    }
    ~http() {}

private:
    unique_ptr<tcpserver> _tser;
    unordered_map<string, func_t> _route;

};
//这里直接先初始化，不放入http类内了。否则回调传参不能适应多方式
unique_ptr<session_manager> ursm = make_unique<session_manager>();

